using System.Runtime.CompilerServices;
#if MYCODE
using BepuUtilities.Vectors;
#else
using System.Numerics;
#endif

namespace BepuUtilities
{
    public static class GatherScatter
    {
        // 待办事项：这里的很多东西都变味了。其他的东西需要搬到更合适的地方。一旦东西烤得再烤一点,以后再来看看这个。

        /// <summary>
        /// 在不使用指针的情况下从向量获取对元素的引用,由于代码生成原因而绕过直接向量访问。这将执行无边界测试！
        /// </summary>
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public static unsafe ref T Get<T>(ref Vector<T> vector, int index) where T : struct
        {
            // TODO：这是一个非常特定于编译器的实现,随着时间的推移应该重新访问它。很有可能它会变得不必要、次优或适得其反。
            return ref Unsafe.Add(ref Unsafe.As<Vector<T>, T>(ref vector), index);
        }

        /// <summary>
        /// 从一个捆绑通道复制到另一个通道。该捆绑包必须是向量类型的连续挡路。
        /// </summary>
        /// <typeparam name="T">复制的捆绑包的类型。</typeparam>
        /// <param name="sourceBundle">要复制的数据的源包。</param>
        /// <param name="sourceInnerIndex">源包内车道的索引。</param>
        /// <param name="targetBundle">要复制的数据的目标捆绑。</param>
        /// <param name="targetInnerIndex">目标捆绑内车道的索引。</param>
        /// <remarks>
        /// 对于性能关键型操作,应该使用专门的实现。这使用步幅等于尚未展开的向量的循环。
        /// </remarks>
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public static void CopyLane<T>(ref T sourceBundle, int sourceInnerIndex, ref T targetBundle, int targetInnerIndex)
        {
            // 请注意截断。当前用于某些大小不能被Vector<int>整除的类型。Count*sizeof(Int)。
            var sizeInInts = (Unsafe.SizeOf<T>() >> 2) & ~BundleIndexing.VectorMask;

            ref var sourceBase = ref Unsafe.Add(ref Unsafe.As<T, int>(ref sourceBundle), sourceInnerIndex);
            ref var targetBase = ref Unsafe.Add(ref Unsafe.As<T, int>(ref targetBundle), targetInnerIndex);

            targetBase = sourceBase;
            // 考虑到jit认为所有相关位都是常量,如果只是根据大小自动展开就好了！
            // 不幸的是,在撰写本文时,jit并非如此。
            // for(int i=Vector<int>.Count;i<sizeInts;i+=Vector<int>.Count)
            // {
            // Unsafe.Add(ref targetBase,i)=Unsafe.Add(ref sourceBase,i);
            // }

            // 为了补偿编译器,我们开始执行以下操作：
            int offset = Vector<int>.Count;
            // 8宽展开,凭经验选择。
            while (offset + Vector<int>.Count * 8 <= sizeInInts)
            {
                Unsafe.Add(ref targetBase, offset) = Unsafe.Add(ref sourceBase, offset); offset += Vector<int>.Count;
                Unsafe.Add(ref targetBase, offset) = Unsafe.Add(ref sourceBase, offset); offset += Vector<int>.Count;
                Unsafe.Add(ref targetBase, offset) = Unsafe.Add(ref sourceBase, offset); offset += Vector<int>.Count;
                Unsafe.Add(ref targetBase, offset) = Unsafe.Add(ref sourceBase, offset); offset += Vector<int>.Count;
                Unsafe.Add(ref targetBase, offset) = Unsafe.Add(ref sourceBase, offset); offset += Vector<int>.Count;
                Unsafe.Add(ref targetBase, offset) = Unsafe.Add(ref sourceBase, offset); offset += Vector<int>.Count;
                Unsafe.Add(ref targetBase, offset) = Unsafe.Add(ref sourceBase, offset); offset += Vector<int>.Count;
                Unsafe.Add(ref targetBase, offset) = Unsafe.Add(ref sourceBase, offset); offset += Vector<int>.Count;
            }
            if (offset + 4 * Vector<int>.Count <= sizeInInts)
            {
                Unsafe.Add(ref targetBase, offset) = Unsafe.Add(ref sourceBase, offset); offset += Vector<int>.Count;
                Unsafe.Add(ref targetBase, offset) = Unsafe.Add(ref sourceBase, offset); offset += Vector<int>.Count;
                Unsafe.Add(ref targetBase, offset) = Unsafe.Add(ref sourceBase, offset); offset += Vector<int>.Count;
                Unsafe.Add(ref targetBase, offset) = Unsafe.Add(ref sourceBase, offset); offset += Vector<int>.Count;
            }
            if (offset + 2 * Vector<int>.Count <= sizeInInts)
            {
                Unsafe.Add(ref targetBase, offset) = Unsafe.Add(ref sourceBase, offset); offset += Vector<int>.Count;
                Unsafe.Add(ref targetBase, offset) = Unsafe.Add(ref sourceBase, offset); offset += Vector<int>.Count;
            }
            if (offset + Vector<int>.Count <= sizeInInts)
            {
                Unsafe.Add(ref targetBase, offset) = Unsafe.Add(ref sourceBase, offset);
            }
        }

        
        /// <summary>
        /// 使用指定类型的默认值清除捆绑车道。捆绑包必须是矢量类型的连续挡路,所有矢量类型共享相同的类型,
        /// 并且第一个向量必须从捆绑包引用所指向的地址开始。
        /// </summary>
        /// <typeparam name="Touter">包含一个或多个向量的类型。</typeparam>
        /// <typeparam name="TVector">要清除的向量的类型。</typeparam>
        /// <param name="bundle">要清除车道的目标捆绑包。</param>
        /// <param name="innerIndex">要清除的目标捆绑内车道的索引。</param>
        /// <remarks>
        /// 对于性能关键型操作,应该使用专门的实现。这使用步幅等于向量的循环。
        /// </remarks>
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public static void ClearLane<TOuter, TVector>(ref TOuter bundle, int innerIndex) where TVector : struct
        {
            // 应该由jit将其合并为单个常量。
            var vectorCount = Unsafe.SizeOf<TOuter>() / Unsafe.SizeOf<Vector<TVector>>();
            ref var laneBase = ref Unsafe.Add(ref Unsafe.As<TOuter, TVector>(ref bundle), innerIndex);
            for (int i = 0; i < vectorCount; ++i)
            {
                Unsafe.Add(ref laneBase, i * Vector<TVector>.Count) = default;
            }
        }

        /// <summary>
        /// 获取对已移位的捆绑包容器的引用,以便每个捆绑包的第一个槽覆盖原始捆绑包引用的给定内部索引。
        /// </summary>
        /// <typeparam name="T">捆绑包容器的类型。</typeparam>
        /// <param name="bundleContainer">捆绑容器,其引用充当已移动引用的基础。</param>
        /// <param name="innerIndex">要使用移动的引用访问的捆绑包内的索引。</param>
        /// <return>移动了包容器引用,覆盖了原始包引用的内部索引。</return>
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public static ref T GetOffsetInstance<T>(ref T bundleContainer, int innerIndex) where T : struct
        {
            //return ref Unsafe.As<float, T>(ref Unsafe.Add(ref Unsafe.As<T, float>(ref bundleContainer), innerIndex));
            ref float ptr = ref Unsafe.As<T, float>(ref bundleContainer);
            ref float ptr1 = ref Unsafe.Add(ref ptr, innerIndex);
            ref T ptr2 = ref Unsafe.As<float, T>(ref ptr1);
            return ref ptr2;
        }

        /// <summary>
        /// 获取对向量引用中第一个元素的引用。
        /// </summary>
        /// <typeparam name="T">矢量保存的值的类型。</typeparam>
        /// <param name="Vector">从中拉取第一个槽值的向量。</param>
        /// <return>引用给定向量的第一个槽中的值。</return>
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public static ref T GetFirst<T>(ref Vector<T> vector) where T : struct
        {
            return ref Unsafe.As<Vector<T>, T>(ref vector);
        }

        public static unsafe void SetFirst(ref Vector<float> vector, float value)
        {
            fixed (void* ptr = &vector)
            {
                float* ptr1 = (float*)ptr;
                *ptr1 = value;
            }
        }

        public static unsafe void SetFirst(ref Vector<int> vector, int value)
        {
            fixed (void* ptr = &vector)
            {
                int* ptr1 = (int*)ptr;
                *ptr1 = value;
            }
        }

        public static unsafe void SetVector(ref Vector<int> vector, int value)
        {
            fixed (void* ptr11 = &vector)
            {
                int* ptr12 = (int*)ptr11;
                for (int n = 0; n < 8/*Vector<int>.Count*/; n++)
                {
                    ptr12[n] = value;
                }
            }
        }

        public static unsafe void SetFirst(ref float value, Vector<float> vector)
        {
            value = vector[0];
        }
    }
}

